import asyncio
import logging
from pymodbus.client import AsyncModbusSerialClient
from pymodbus.framer import FramerType

# 配置串口参数
SERIAL_PORT = "COM7"  # 主站串口
BAUDRATE = 9600
UNIT_ID = 1  # 从站设备地址

# 设置日志
logging.basicConfig(
    format="%(asctime)s [%(levelname)s] %(message)s",
    level=logging.DEBUG
)

# 启用 pymodbus 的通信日志
logging.getLogger("pymodbus").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.client").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.protocol").setLevel(logging.DEBUG)
logging.getLogger("pymodbus.transaction").setLevel(logging.DEBUG)

async def read_discrete_inputs():
    """读取离散输入（功能码2）"""
    client = AsyncModbusSerialClient(
        port=SERIAL_PORT,
        baudrate=BAUDRATE,
        stopbits=1,
        bytesize=8,
        parity='N',
        timeout=1,
        framer=FramerType.RTU
    )
    
    try:
        await client.connect()
        if not client.connected:
            logging.error("无法连接到从站设备")
            return False

        # 读取功能码2（离散输入），地址0x10~0x15（对应Modbus地址17~22）
        rr = await client.read_discrete_inputs(address=0x00, count=16, slave=UNIT_ID)
        if rr.isError():
            logging.error(f"读取寄存器失败: {rr}")
            return False
        else:
            logging.info(f"读取到的离散输入值: {rr.bits}")
            return True
    except Exception as e:
        logging.error(f"读取过程中发生错误: {e}")
        return False
    finally:
        try:
            if client and client.connected:
                await client.close()
        except Exception as e:
            logging.debug(f"关闭连接时发生错误: {e}")

async def monitor_connection():
    """持续监控连接状态"""
    logging.info("开始持续检测连接性...")
    logging.info(f"目标串口: {SERIAL_PORT}, 波特率: {BAUDRATE}, 设备地址: {UNIT_ID}")
    
    while True:
        try:
            logging.info("尝试连接设备...")
            success = await read_discrete_inputs()
            
            if success:
                logging.info("✅ 连接成功并成功读取数据！")
                # 可以选择继续监控或退出
                # break  # 如果只想读取一次就退出，取消注释这行
            else:
                logging.warning("❌ 连接失败或读取失败，1秒后重试...")
                await asyncio.sleep(1)
                
        except KeyboardInterrupt:
            logging.info("用户中断，程序退出")
            break
        except Exception as e:
            logging.error(f"监控过程中发生错误: {e}")
            await asyncio.sleep(1)

if __name__ == "__main__":
    try:
        asyncio.run(monitor_connection())
    except KeyboardInterrupt:
        logging.info("主站程序已退出")